Skip to content

Conversation

@Dentosal
Copy link
Member

@Dentosal Dentosal commented Jan 5, 2026

Implements dynamic storage instructions as described in FuelLabs/fuel-specs#640

The storage initialization in Create transactions is left as-is, i.e. it only allows 32 byte slots. This feature isn't used much, and I don't think it's worth it to continue supporting.

Checklist

  • Breaking changes are clearly marked as such in the PR description and changelog
  • New behavior is reflected in tests
  • If performance characteristic of an instruction change, update gas costs as well or make a follow-up PR for that
  • The specification matches the implemented behavior (link update PR if changes are needed)

Before requesting review

  • I have reviewed the code myself
  • I have created follow-up issues caused by this PR and linked them here

@Dentosal Dentosal self-assigned this Jan 5, 2026
@Dentosal Dentosal marked this pull request as ready for review January 12, 2026 12:15
@cursor
Copy link

cursor bot commented Jan 12, 2026

PR Summary

Introduces variable-sized contract storage and updates the VM, assembler, and consensus to support it.

  • Adds storage opcodes: SCLR, SRDD, SRDI, SWRD, SWRI, SUPD, SUPI, SPLD, SPCP; SRW gains an immediate offset
  • Updates gas costs to V7 with per-op dependent costs for new storage ops; integrates throughout gas accessors
  • Adds ScriptParametersV2 with max_storage_slot_length; ScriptParameters::DEFAULT now V2; exposes getters and test-helpers
  • Implements dynamic storage in VM: read/write/update/preload paths, storage preload buffer, bounds checks, and register write helper; clears preload on call/ret
  • Adds StorageOutOfBounds panic reason; adapts predicate/allowed opcodes and tests; minor asm recursion limit
  • Adjusts tests to new behavior (including srw offset) and adds extensive storage op tests

Written by Cursor Bugbot for commit 47d787d. This will update automatically on new commits. Configure here.

self,
interpreter: &mut Interpreter<M, S, Tx, Ecal, V>,
) -> IoResult<ExecuteState, S::DataError> {
let (a, b, c, d) = self.unpack();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice if we used readable names here like in hte opcode definition

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in eec4b1d

.storage
.contract_state(&contract_id, &key)
.map_err(RuntimeError::Storage)?
.map(|v| v.as_ref().as_ref().to_vec())
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can convert the value into owned type (because, under the hood, it is already owned). Overwise you create vector two times(one when we create value, and another here).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. f07f99e

Comment on lines +105 to +107
let offset = if offset == u64::MAX {
value.len()
} else {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did we specif this behaviour in the specification?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep.

Passing in u64::MAX in $rC will cause the write to happen at the end of the slot, without needing to read the slot length first.

let dst = self.memory.as_mut().write(owner, dst_ptr, len)?;
let value = self
.storage
.contract_state(&contract_id, &key)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it is better to use read_bytes here? In this case we will avoud creation of the vector on the fuel-core side

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure which read_bytes you're talking about?

@Dentosal Dentosal requested a review from xgreenx January 16, 2026 14:23
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

interpreter: &mut Interpreter<M, S, Tx, Ecal, V>,
) -> IoResult<ExecuteState, S::DataError> {
match self {
match dbg!(self) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Debug macro left in production instruction execution code

High Severity

A dbg!(self) macro was accidentally left in the main Execute::execute implementation for Instruction. This will print every single VM instruction to stderr during execution, causing significant performance degradation and producing unwanted debug output in production. The match dbg!(self) should be match self.

Fix in Cursor Fix in Web

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants